package io.gitee.hefren.hhconfig.client.utils;

import com.google.common.collect.Sets;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanExpressionContext;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.Scope;
import org.springframework.util.StringUtils;

import java.util.Objects;
import java.util.Set;
import java.util.Stack;

/**
 * @Date 2024/6/4
 * @Author lifei
 */
public class PlaceholderHelper {

    private static final String PLACEHOLDER_PREFIX = "${";
    private static final String PLACEHOLDER_SUFFIX = "}";
    private static final String EXPRESSION_PREFIX = "#{";
    private static final String EXPRESSION_SUFFIX = "}";
    private static final String SIMPLE_SUFFIX = "{";
    private static final String VALUE_SEPORATOR = ":";

    private PlaceholderHelper(){}

    /**
     *
     * @param configurableBeanFactory
     * @param beanName
     * @param placeholder
     * @return
     */
    public Object getSpringFiledValue(ConfigurableBeanFactory configurableBeanFactory, String beanName, String placeholder) {
        // 初步解析@Value中的表达式
        String strVal = configurableBeanFactory.resolveEmbeddedValue(placeholder);
        // 进一步解析
        BeanDefinition beanDefinition = null;
        if (configurableBeanFactory.containsBean(beanName)) {
            beanDefinition = configurableBeanFactory.getMergedBeanDefinition(beanName);
        }
        return getBeanDefinitonSpringValue(configurableBeanFactory, beanDefinition, strVal);
    }

    /**
     * 再次解析
     * @param configurableBeanFactory
     * @param beanDefinition
     * @param strVal
     * @return
     */
    private Object getBeanDefinitonSpringValue(ConfigurableBeanFactory configurableBeanFactory, BeanDefinition beanDefinition, String strVal) {
        if (Objects.isNull(configurableBeanFactory.getBeanExpressionResolver())) {
            return strVal;
        }
        Scope scope = null;
        if (Objects.nonNull(beanDefinition) && Objects.nonNull(beanDefinition.getScope())) {
             scope = configurableBeanFactory.getRegisteredScope(beanDefinition.getScope());
        }
        return configurableBeanFactory.getBeanExpressionResolver().evaluate(strVal, new BeanExpressionContext(configurableBeanFactory, scope));
    }

    private static class PlaceholderHelperHolder{
        private static final PlaceholderHelper INSTANCE = new PlaceholderHelper();
    }
    public static PlaceholderHelper instance() {
        return PlaceholderHelperHolder.INSTANCE;
    }

    /**
     * 判断 ${}
     * @param placeholder
     * @return
     */
    private boolean isNormalPlaceholder(String placeholder) {
        return Objects.nonNull(placeholder)
                && placeholder.startsWith(PLACEHOLDER_PREFIX)
                && placeholder.endsWith(PLACEHOLDER_SUFFIX);
    }

    /**
     * 判断 #{..${}...}
     * @param expression
     * @return
     */
    private boolean isExpressionContainsPlaceholder(String expression) {
        return Objects.nonNull(expression)
                && expression.startsWith(EXPRESSION_PREFIX)
                && expression.endsWith(EXPRESSION_SUFFIX)
                && expression.contains(PLACEHOLDER_PREFIX);
    }


    /**
     * 提取 keys
     * ${k.v} ==> k.v
     * ${${k.v}} ==> k.v
     * SPEL: #{new String(${k.v:${k2.v2}....${k3.v3}})} ===> k.v, k2.v2, k3.v3
     * @param placeholder
     * @return
     */
    public Set<String> extractPlaceholderKeys(String placeholder) {
        Set<String> result = Sets.newHashSet();
        // 判断 是否是正常的 ${...}, 或者是 #{...${}...}
        if (!isNormalPlaceholder(placeholder) && !isExpressionContainsPlaceholder(placeholder)) {
            return result;
        }
        Stack<String> stack = new Stack<>();
        stack.push(placeholder);
        while (!stack.isEmpty()) {
            String text = stack.pop();
            int placeholderBeginIndex = text.indexOf(PLACEHOLDER_PREFIX);
            if (placeholderBeginIndex == -1) {
                result.add(text);
                continue;
            }
            // 获取${} 中 } 的索引
            int placeholderEndIndex = findPlaceholderEndIndex(text, placeholderBeginIndex);
            if (placeholderEndIndex == -1) {
                continue;
            }
            // 候选值
            String candidateText = text.substring(placeholderBeginIndex + PLACEHOLDER_PREFIX.length(), placeholderEndIndex);
            // 如果候选值 ${}
            if (candidateText.startsWith(PLACEHOLDER_PREFIX)) {
                stack.push(candidateText);
            } else {
                // k.v:${}
                // 分隔符 : 的位置
                int seporatorIndex = candidateText.indexOf(VALUE_SEPORATOR);
                if (seporatorIndex == -1) {
                    stack.push(candidateText);
                } else {
                    stack.push(candidateText.substring(0, seporatorIndex));
                    // k.v:1235${k1.v1}
                    // 处理分隔符后面的内容
                    // 后面的部分
                    // ${k1.v1}
                    String subText = normalToPlaceholder(candidateText.substring(seporatorIndex+1));
                    if (StringUtils.hasText(subText)) {
                        stack.push(subText);
                    }
                }
            }
            // ${v1}...${} ===> ${v2}
            String remainText = normalToPlaceholder(text.substring(placeholderEndIndex+1));
            if (StringUtils.hasText(remainText)) {
                stack.push(remainText);
            }
        }
        return result;
    }

    private String normalToPlaceholder(String text) {
        int placeholderBeginIndex = text.indexOf(PLACEHOLDER_PREFIX);
        if (placeholderBeginIndex == -1) {
            return null;
        }
        int placeholderEndIndex = text.lastIndexOf(PLACEHOLDER_SUFFIX);
        if (placeholderEndIndex == -1) {
            return null;
        }
        // ${}
        return text.substring(placeholderBeginIndex, placeholderEndIndex+1);
    }

    private int findPlaceholderEndIndex(String text, int placeholderBeginIndex) {
        int placeholderEndIndex = placeholderBeginIndex + PLACEHOLDER_PREFIX.length();
        int withinPlaceholderNum = 0;
        while (placeholderEndIndex < text.length()) {
            // {
            if (StringUtils.substringMatch(text, placeholderEndIndex, SIMPLE_SUFFIX)) {
                // {
                withinPlaceholderNum ++;
                placeholderEndIndex = placeholderEndIndex + SIMPLE_SUFFIX.length();
            } else if (StringUtils.substringMatch(text, placeholderEndIndex, PLACEHOLDER_SUFFIX)) {
                // } 子集的结尾，也可能是 真实值的结果
                if (withinPlaceholderNum > 0) {
                    // 子集的结果
                    withinPlaceholderNum --;
                    placeholderEndIndex = placeholderEndIndex + PLACEHOLDER_SUFFIX.length();
                } else {
                    return placeholderEndIndex;
                }
            } else {
                placeholderEndIndex ++;
            }
        }
        return -1;
    }

}
